package com.zombie.logic.object;

import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Animation2D;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.RayCastCallback;
import com.zombie.Constants;
import com.zombie.ResourceManager;
import com.zombie.effect.ImageEffect;
import com.zombie.effect.ScalingImageEffect;
import com.zombie.logic.Formulas;
import com.zombie.logic.core.ZombieWorld;
import com.zombie.logic.core.box2d.ListQueryCallback;
import com.zombie.logic.core.box2d.RayCastRequest;
import com.zombie.logic.enums.AnimationType;
import com.zombie.state.GameState;
import com.zombie.util.ThreadPoolManager;
import com.zombie.util.Utils;

public class Zombie extends LiveObject {
	
	Animation2D dieAnim;

	public Zombie(float x, float y){
		this(x,y,"zombie1");
	}
	
	public Zombie(float x, float y, String image){
		this(x,y,image,28,28);
	}
	
	public Zombie(float x, float y, String image, int w, int h){
		super(x,y);
		target = GameState.getInstance().player;
		name="Zombie";
		this.image = image;
		size.set(w,h);
		dieAnim = ResourceManager.getAnimation(image+"_die").copy();
		dieAnim.setPlayMode(Animation2D.NORMAL);
		GameState.zombies++;
		createBody();
	}

	@Override
	public void update(float delta) {
		super.update(delta);
		if (isDead()){
			if (dieAnim.isAnimationFinished(GameState.time-deathTime)){
				addToBackground();
				remove();
				GameState.zombies--;
				dieAnim = null;
			}
			return;
		}
		if (wait)
			return;
		
//		if (lastMoveTimer+1000  < GameState.time){
////			if (path == null) {
////				findPath();
////			} else {
//				if (!checkForStaticTarget()){
//					wait = true;
//					lastMoveTimer = GameState.time;
//					ThreadPoolManager.getInstance().scheduleGeneral(new Runnable(){
//
//						@Override
//						public void run() {
//							wait = false;
//							lastMoveTimer = GameState.time;
//						}}, 1000);
//				}
//				
////			}
//		}
		
		if (target != null){
			if (target.position.dst(position) > (size.x+size.y)/2){
				animation = AnimationType.MOVE;
				angle = getAngleToObject(target);
				float x1 = getVelocity()*MathUtils.cos(MathUtils.degRad*angle);
				float y1 = getVelocity()*MathUtils.sin(MathUtils.degRad*angle);
				body.applyForceToCenter(x1,y1);
			} else {
				if (target instanceof LiveObject)
					hit();
			}
//			if (target instanceof Point){
//				if (target.position.dst(position) < 16){
//					target = null;
//					currentStep++;
//					if (currentStep>=path.getLength()-1){
//						currentStep = 0;
//						path = null;
//						target = GameState.player;
//					} else{
//						target = new Point(path.getStep(currentStep).getX()*Constants.TILESIZE+Constants.TILESIZE/2,path.getStep(currentStep).getY()*Constants.TILESIZE+Constants.TILESIZE/2);
//					}
//					return;
//				}
//			}
//			else if (target instanceof LiveObject){
//				if (target.position.dst(position) < (size.x+size.y)/2){
//					hit();
//				}
//			}
//			if(animation == AnimationType.MOVE){
//				if (lastStep+stepTime < GameState.time+Utils.rnd.nextInt(50)){
//					if (intersects(GameState.getInstance().offsetX, GameState.getInstance().offsetY, Constants.SCREEN_WIDTH, Constants.SCREEN_HEIGHT)){
//						stepSound();
//					}
//				}
//			}
		} else {
			animation = AnimationType.STAND;
			if (Utils.rnd.nextInt(1000) < 5){
				target = new Point(position.x+(-100+Utils.rnd.nextInt(200)),position.y+(-100+Utils.rnd.nextInt(200)));
			}
		}
	}

	private boolean checkForStaticTarget() {
		boolean result = false;
		ListQueryCallback query = new ListQueryCallback();
		ZombieWorld.world.QueryAABB(query,position.x-Constants.TILESIZE/2,position.y-Constants.TILESIZE/2,
				position.x+Constants.TILESIZE,position.y+Constants.TILESIZE);
		for(Body b : query.bodyes){
			if (b.getUserData() instanceof StaticObject){
				((StaticObject)b.getUserData()).life -= getDamage();
				lastMoveTimer = GameState.time;
				result = true;
				break;
			}	
		}
		query.bodyes.clear();
		query.bodyes = null;
		return result;
	}

	protected void findPath() {
//		path = GameState.pathFinder.findPath(this,
//				(int) pos.x/Constants.TILESIZE, (int) pos.y/Constants.TILESIZE,
//				(int) target.pos.x/Constants.TILESIZE, (int) target.pos.y/Constants.TILESIZE);
//		path = Utils.correctPath(path);
//		if (path != null){
//			target = new Point(path.getStep(1).getX()*Constants.TILESIZE+Constants.TILESIZE/2,path.getStep(0).getY()*Constants.TILESIZE+Constants.TILESIZE/2);
//			ThreadPoolManager.getInstance().scheduleGeneral(new PlayerFinder(), 10000);
//		}
	}	

	protected void hit() {
		if (GameState.time < lastHit+hitTime)
			return;
		lastHit = GameState.time;
		if (target instanceof LiveObject)
			Formulas.calcDamage(getDamage(), this, (LiveObject) target);
	}

	private void addToBackground() {
		ScalingImageEffect eff2 = new ScalingImageEffect();
		eff2.setBounds(position.x, position.y, ResourceManager.getImage("meat_"+Utils.rnd.nextInt(3)));	
		eff2.maxScale = 2.f;
		eff2.scaleVelocity = -0.05f;
		ZombieWorld.addEffect(eff2);
		
//		if (Util.rnd.nextBoolean()){
		ImageEffect eff = new ImageEffect();
		eff.image = dieAnim.getFrame(dieAnim.frameCount()-1);
		eff.setBounds(position.x-size.x/2, position.y-size.y/2, size.x,size.y);
		eff.angle = angle;
		ZombieWorld.addEffect(eff);
//		} else {
//			toParts(0.1f,dieAnim.getCurrentFrame());
//		}
	}

	@Override
	public void draw(SpriteBatch batch, ShapeRenderer shapeBatch) {
		TextureRegion region;
		if (animation == AnimationType.MOVE){
			Animation a = ResourceManager.getAnimation(image+"_move");
			 region = a.getKeyFrame(GameState.time);
			batch.draw(region, position.x-size.x/2, position.y-size.y/2, size.x/2, size.y/2, size.x, size.y, 1, 1, angle);
		}else if (animation == AnimationType.STAND){
			Animation a = ResourceManager.getAnimation(image+"_stand");
			region = a.getKeyFrame(GameState.time);
			batch.draw(region, position.x-size.x/2, position.y-size.y/2, size.x/2, size.y/2, size.x, size.y, 1, 1, angle);		
		}else if (animation == AnimationType.DIE){
			region = dieAnim.getKeyFrame(GameState.time-deathTime);
			batch.draw(region, position.x-size.x/2, position.y-size.y/2, size.x/2, size.y/2, size.x, size.y, 1, 1, angle);		
		}
//		g.rotate(pos.x, pos.y, (float) angle);
//		if (animation == AnimationType.STAND)
//			ResourceManager.getImage(image+"_stand").draw(pos.x-size.x/2, pos.y-size.y/2, size.x, size.y);
//		else if (animation == AnimationType.MOVE)
//			ResourceManager.getAnimation(image+"_move").draw(pos.x-size.x/2, pos.y-size.y/2,size.x, size.y);
//		else if (animation == AnimationType.DIE)
//			dieAnim.draw(pos.x-size.x/2, pos.y-size.y/2, size.x, size.y);
//		g.rotate(pos.x, pos.y, (float) -angle);	
//
//		if (target instanceof Point)
//			g.fillOval(target.pos.x-4, target.pos.y-4, 8, 8);
	}

	@Override
	protected void onHit(GameObject damager) {
		if (damager != null)
			target = damager;
//		path = null;
		
		if (Utils.rnd.nextInt(4) == 0)
			playSound();
	}
	
	protected void playSound() {
		ResourceManager.getSound("zombie_"+Utils.rnd.nextInt(6)).play();
	}
	
	@Override
	protected void doDie(GameObject damager, int value){
		super.doDie(damager, value);
	}
	/** If mob go through path and player is on the way
	 *  set target to Player or continue finding*/
	class PlayerFinder implements Runnable,RayCastCallback{

		@Override
		public void run() {
			if (target instanceof Player)
				return;
			RayCastRequest request = new RayCastRequest();
			request.callback = this;
			request.start = new Vector2(position.x,position.y);
			request.finish = new Vector2(GameState.getInstance().player.position.x,GameState.getInstance().player.position.y);
			ZombieWorld.raycasts.add(request); 
		}
		
		@Override
		public float reportRayFixture(Fixture fixture, Vector2 point, Vector2 normal,
				float fraction) {
			if (fixture.getBody().getUserData() == GameState.getInstance().player){
				target = GameState.getInstance().player;
//				path = null;
			} else
				ThreadPoolManager.getInstance().scheduleGeneral(this, 5000);
			return 0;
		}

	}

	
}
